package de.szut.dqi10.brailletouchscreenreader.display;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.LinkedList;

import de.szut.brailletouchscreenreader.R;
import de.szut.dqi10.brailletouchscreenreader.braillechar.BrailleChar;
import de.szut.dqi10.brailletouchscreenreader.textprocessing.FileReader;
import de.szut.dqi10.brailletouchscreenreader.textprocessing.TextToBrailleConverter;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.AssetManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.view.WindowManager;

/**
 * The main activity that displays a BrailleView
 * @author Marco Jedzig, Simon Grafenhorst, Felix Pusch
 *
 */
public class BrailleMainActivity extends Activity {
	
	private static final String TAG = "BrailleMainActivity";
	private static final String PREFERENCES_DEFAULT_VIBRATEMODE = "0";
	private static final String PREFERENCES_DEFAULT_BUTTONSIZEX = "80";
	private static final String PREFERENCES_DEFAULT_BUTTONSIZEY = "80";
	private static final boolean PREFERENCES_DEFAULT_AUTONEXT = true;
	private static final boolean PREFERENCES_DEFAULT_FULLSCREEN = true;
	private static final String PREFERENCES_DEFAULT_INPUTFILE = "";
	
	private FileReader fileReader;
	private File inputFile;
	
	private TextToBrailleConverter converter;
	private LinkedList<BrailleChar> toDisplay;
	private int currentDisplayedCharIndex = -1; //before the first character
	
	private String vibrateModePreferenceValue;
	private String buttonsizeXPrefValue;
	private String buttonsizeYPrefValue;
	private String filePrefValue;
	private boolean autonextPrefValue;
	private boolean fullscreenPrefValue;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		Log.i(TAG, "Created a " + TAG);
		
		//Enable true fullscreen
		this.requestWindowFeature(Window.FEATURE_NO_TITLE);
		this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
		
		setContentView(R.layout.braille_reader_activity);
		
		converter = new TextToBrailleConverter();
		converter.setAlphabet(loadBrailleAlphabetFromAsset());
		
		displayPrevBrailleChar(); //need to use this since we want an empty character
		
		fileReader = new FileReader();
	}

	/**
	 * Loads the BrailleAlphabet from file.
	 * 
	 * @return a HashMap of the String expression mapped to a Byte
	 */
	private HashMap<String, Byte> loadBrailleAlphabetFromAsset() {
		Log.i(TAG, "Loading Braille Alphabet from Asset");
		
		HashMap<String, Byte> alphabet = new HashMap<String, Byte>();
		AssetManager assetManager = getAssets();
		try {
			InputStream is = assetManager.open(getString(R.string.braillealphabet_filename));
			String csvseparator = getString(R.string.braillealphabet_csvseparator);
			BufferedReader br = new BufferedReader(new InputStreamReader(is));
			String line;
			while (br.ready()) {
				line = br.readLine();
				Byte braille = Byte.parseByte(line.split(csvseparator)[1]);
				alphabet.put(line.split(csvseparator)[0].trim(), braille);
			}
			br.close();
		} catch (IOException e) {
			Log.e(TAG, "Error while loading alphabet from asset: " + e.getLocalizedMessage());
		}
		return alphabet;

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		Log.i(TAG, "Creating options Menu");
		//Inflate our Menu
		getMenuInflater().inflate(R.menu.braille_reader_activity, menu);
		return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		Log.i(TAG, "OptionItem selected" + ", Item: " + item.toString());
		
		switch(item.getItemId()) {
		case R.id.menu_settings:
			Log.i(TAG, "Attempt to show settings");
			showSettingsView();
			return true;
		case R.id.menu_reloadfile:
			Log.i(TAG, "Attempt to reload file");
			loadContentFromFile(filePrefValue);
			return true;
		case R.id.menu_restartfile:
			Log.i(TAG, "Attempt to restart file");
			currentDisplayedCharIndex = -1;
			displayNextBrailleChar();
			//loadContentFromFile(inputFile);
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}

	@Override
	public void onResume() {
		super.onResume();
		
		Log.i(TAG, "Resuming " + TAG);
		
		getAndApplyPreferences();
	}
	
	/**
	 * Pulls the current preference values from the sharedPreferences.
	 * Called in onResume() to adjust the preferences after they were changed 
	 * in the Preference Activity and the BrailleReader Activity resumed.
	 */
	private void getAndApplyPreferences() {
		BrailleView brailleView = (BrailleView) findViewById(R.id.braille_view);
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(this);

		vibrateModePreferenceValue = sp.getString(
				BrailleSettingsActivityFragment.PREF_VIBRATEMODE_KEY,
				PREFERENCES_DEFAULT_VIBRATEMODE);
		brailleView.setVibrateMode(Integer.parseInt(vibrateModePreferenceValue));

		buttonsizeXPrefValue = sp.getString(
				BrailleSettingsActivityFragment.PREF_BUTTONSIZEX_KEY,
				PREFERENCES_DEFAULT_BUTTONSIZEX);
		buttonsizeYPrefValue = sp.getString(
				BrailleSettingsActivityFragment.PREF_BUTTONSIZEY_KEY,
				PREFERENCES_DEFAULT_BUTTONSIZEY);

		brailleView.setScale(
				Integer.parseInt(buttonsizeXPrefValue),
				Integer.parseInt(buttonsizeYPrefValue));

		autonextPrefValue = sp.getBoolean(
				BrailleSettingsActivityFragment.PREF_AUTONEXT_KEY,
				PREFERENCES_DEFAULT_AUTONEXT);
		brailleView.setAutonext(autonextPrefValue);

		fullscreenPrefValue = sp.getBoolean(
				BrailleSettingsActivityFragment.PREF_FULLSCREEN_KEY,
				PREFERENCES_DEFAULT_FULLSCREEN);
		brailleView.setFullscreen(fullscreenPrefValue);

		filePrefValue = sp.getString(
				BrailleSettingsActivityFragment.PREF_INPUTFILE_KEY,
				PREFERENCES_DEFAULT_INPUTFILE);
		if (filePrefValue != "") {
			if (inputFile != null ) {
				if (!inputFile.getPath().equals(filePrefValue)) {
					loadContentFromFile(filePrefValue); //before filePrefValue
					
				}
			} else { loadContentFromFile(filePrefValue); }
		}
		
		Log.i(TAG, "Pulled these Preferences: " + "\n"
				+ "vibrateMode: " + vibrateModePreferenceValue + "\n"
				+ "buttonSizeX: " + buttonsizeXPrefValue + "\n"
				+ "buttonSizeY: " + buttonsizeYPrefValue + "\n"
				+ "autonext: " + autonextPrefValue + "\n"
				+ "fullscreen: " + fullscreenPrefValue + "\n"
				+ "inputfile: " + filePrefValue);
	}

	/**
	 * Load Content from the file at the given path
	 * @param filepath path to the file to read from
	 */
	private void loadContentFromFile(String filepath) {
		inputFile = new File(filepath);
		if (!inputFile.isDirectory()) {
			loadContentFromFile(inputFile);
		} else {
			Log.e(TAG, "Cannot read file contents from a directory");
		}
	}
	
	/**
	 * Load Content from the given file
	 * @param file the file to read from
	 */
	private void loadContentFromFile(File file) {
		Log.i(TAG, "Loading content from: " + file.getAbsolutePath());
		if (file != null) {
			String content = fileReader.getContent(file);
			toDisplay = converter.getStringAsBraille(content);
			currentDisplayedCharIndex = -1;
			displayNextBrailleChar();
		}
	}

	/**
	 * Show/Display a BrailleSettingsView
	 */
	private void showSettingsView() {
		Log.i(TAG, "Starting Settings View");
		startActivity(new Intent(this,BrailleSettingsActivity.class));
	}
	
	@Override
	public boolean dispatchKeyEvent(KeyEvent event) {
	    int action = event.getAction();
	    int keyCode = event.getKeyCode();
	        switch (keyCode) {
	        case KeyEvent.KEYCODE_VOLUME_UP:
	            if (action == KeyEvent.ACTION_UP) {
	            	Log.i(TAG, "KeyEvent.VOLUME_UP");
	            	displayNextBrailleChar(); 
	            }
	            return true;
	        case KeyEvent.KEYCODE_VOLUME_DOWN:
	            if (action == KeyEvent.ACTION_DOWN) {
	            	Log.i(TAG, "KeyEvent.VOLUME_DOWN");
	            	displayPrevBrailleChar();
	            }
	            return true;
	        default:
	            return super.dispatchKeyEvent(event);
	        }
	    }

	/**
	 * Displays the next BrailleChar in the class attribute LinkedList<BrailleChar> toDisplay.
	 * Displays an "empty" BrailleChar if there is not next BrailleChar in the List.
	 */
	public void displayNextBrailleChar() {
		currentDisplayedCharIndex++;
		if (toDisplay != null) {
			BrailleView view = ((BrailleView) findViewById(R.id.braille_view));
			if (currentDisplayedCharIndex >= toDisplay.size()) {
				currentDisplayedCharIndex = toDisplay.size();
				view.setBrailleChar(new BrailleChar((byte)0));
				Log.i(TAG, "End of file reached. Displaying empty BrailleChar!");
			} else {
				view.setBrailleChar(toDisplay.get(currentDisplayedCharIndex));
				Log.i(TAG, "Displaying character at index: " + String.valueOf(currentDisplayedCharIndex));
			}
		}
	}
	
	/**
	 * Displays the previous BrailleChar in the class attribute LinkedList<BrailleChar> toDisplay.
	 * Displays an "empty" BrailleChar if there is not previous BrailleChar in the List.
	 */
	public void displayPrevBrailleChar() {
		currentDisplayedCharIndex--;
		BrailleView view = ((BrailleView) findViewById(R.id.braille_view));
		if (currentDisplayedCharIndex < 0 || toDisplay == null) {
			currentDisplayedCharIndex = -1;
			Log.i(TAG, "Index is before the first character. Displaying empty BrailleChar!");
			view.setBrailleChar(new BrailleChar((byte)0));
		} else {
			view.setBrailleChar(toDisplay.get(currentDisplayedCharIndex));
			Log.i(TAG, "Display character at index: " + String.valueOf(currentDisplayedCharIndex));
		}
	}
}
